﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using orz.mouxianyu.Extensions;
using orz.mouxianyu.Extensions.Exceptions;
using Serilog;

namespace orz.mouxianyu
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            //业务逻辑注入
            services.AddApiCoreService();
            //注入swagger接口调试工具
            services.AddSwaggerDocumentation();
            //注入API corers跨域
            services.AddApiCors();
            //SqlConnection注入
            services.AddSqlClient(Configuration);
            //注入context
            services.AddHttpContextAccessor();
            // 设置 jwt 验证模块
            services.AddJwtAuthentication(Configuration);
            //配置 全局拦截器
            var authzPolicy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();

            services.AddMvcCore(opt =>
            {
                opt.Filters.Add(new AuthorizeFilter(authzPolicy));
            })
                .AddApiExplorer()
                .AddAuthorization()
                .AddJsonFormatters(opts =>
                {
                    opts.Formatting = Formatting.Indented;
                    opts.TypeNameHandling = TypeNameHandling.None;//不包含 对象类型名称
                    opts.NullValueHandling = NullValueHandling.Include;//序列化是包含null 值
                    opts.ContractResolver = new CamelCasePropertyNamesContractResolver();//json 首字母小写 格式处理
                    //opts.ContractResolver = new DefaultContractResolver();//json默认处理  json处理方式只能启用一个
                    //日期类型默认格式化处理  
                    opts.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat;
                    opts.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                })
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            //services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            Log.Information("Startup done running...");
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseCookiePolicy();

            //使用swagger
            app.UseSwaggerDocumentation();
            //使用跨域
            app.UseCors("api");
            app.UseHttpsRedirection();
            //使用 jwt 授权认证配置。
            app.UseAuthentication();
            //开启静态文件（wwwroot目录）
            app.UseStaticFiles();
            //封装报错信息
            app.UseMiddleware<ErrorWrappingMiddleware>();
            //websocket
            var webSocketOptions = new WebSocketOptions()
            {
                KeepAliveInterval = TimeSpan.FromSeconds(120),
                ReceiveBufferSize = 4 * 1024
            };
            //WebSocket 源限制
            //webSocketOptions.AllowedOrigins.Add("https://orz.mouxianyu.com");
            //webSocketOptions.AllowedOrigins.Add("https://www.orz.mouxianyu.com");
            app.UseWebSockets(webSocketOptions);
            app.Use(async (context, next) =>
            {
                if (context.Request.Path == "/ws")
                {
                    if (context.WebSockets.IsWebSocketRequest)
                    {
                        WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
                        await Echo(context, webSocket);
                    }
                    else
                    {
                        context.Response.StatusCode = 400;
                    }
                }
                else
                {
                    await next();
                }

            });
            app.UseMvc();
        }
        private async Task Echo(HttpContext context, WebSocket webSocket)
        {
            var buffer = new byte[1024 * 4];
            WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            while (!result.CloseStatus.HasValue)
            {
                await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);

                result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            }
            await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
        }
    }
}
